package com.haibara.codesubmiteval.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.haibara.codesubmiteval.common.ErrorCode;
import com.haibara.codesubmiteval.constant.AuthConstant;
import com.haibara.codesubmiteval.constant.RedisKeyConstant;
import com.haibara.codesubmiteval.exception.ThrowUtils;
import com.haibara.codesubmiteval.mapper.QuestionMapper;
import com.haibara.codesubmiteval.mapper.UserMapper;
import com.haibara.codesubmiteval.model.entity.Question;
import com.haibara.codesubmiteval.model.entity.User;
import com.haibara.codesubmiteval.model.vo.Top10VO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Redis 缓存修复工具
 *
 * @Author: mengyu
 * @Date: 2025/3/5
 */
@Component
@Slf4j
public class RedisRecoveryUtil {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private UserMapper userMapper;
    @Resource
    private QuestionMapper questionMapper;

    public Set<String> recoveryUserQuestionSet(Long userId) {
        // 删除旧值
        stringRedisTemplate.delete(RedisKeyConstant.getCompleteKey(RedisKeyConstant.userAcceptedQuestionIdsSet, userId.toString()));
        // 修复
        User user = userMapper.selectById(userId);
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR, userId + "对应用户不存在");
        HashSet<Long> questionIdSet = new HashSet<>(JSONUtil.toList(user.getAcceptedQuestionIds(), Long.class));
        for (Long id : questionIdSet) {
            stringRedisTemplate.opsForSet().add(
                    RedisKeyConstant.getCompleteKey(RedisKeyConstant.userAcceptedQuestionIdsSet, userId.toString()),
                    id.toString()
            );
        }
        Set<String> result = stringRedisTemplate.opsForSet().members(
                RedisKeyConstant.getCompleteKey(
                        RedisKeyConstant.userAcceptedQuestionIdsSet,
                        userId.toString()
                )
        );
        ThrowUtils.throwIf(result == null || result.isEmpty(), ErrorCode.SYSTEM_ERROR, "Redis数据不存在 : UserQuestionSet:" + userId);
        log.info("UserId = {}, QuestionSet修复完成", userId);
        return result;
    }

    public String recoveryQuestionNum() {
        stringRedisTemplate.delete(RedisKeyConstant.questionNumber);
        int questionNumber = questionMapper.getQuestionNumber();
        stringRedisTemplate.opsForValue().set(RedisKeyConstant.questionNumber, String.valueOf(questionNumber));
        String value = stringRedisTemplate.opsForValue().get(RedisKeyConstant.questionNumber);
        ThrowUtils.throwIf(value == null || StrUtil.isBlankIfStr(value), ErrorCode.SYSTEM_ERROR, "Redis数据不存在 : QuestionNum");
        log.info("QuestionNumber修复完成");
        return value;
    }

    public Set<ZSetOperations.TypedTuple<String>> recoveryTop() {
        stringRedisTemplate.delete(RedisKeyConstant.top10);
        // 将数据库中用户完成题目id存入Redis
        List<User> users = userMapper.selectList(null); // 从数据库读取数据
        // ZSet用于构建榜单
        ZSetOperations<String, String> zSetOperations = stringRedisTemplate.opsForZSet();
        for (User user : users) {
            // 管理员不参与Top10
            if (user.getUserRole().equals(AuthConstant.USER)) {
                zSetOperations.add(
                        RedisKeyConstant.top10,  //key
                        JSONUtil.toJsonStr(
                                Top10VO.builder()
                                        .userId(user.getId())
                                        .build()
                        )  //value
                        ,
                        user.getScore()  //score
                );
            }
        }
        Set<ZSetOperations.TypedTuple<String>> typedTuples = zSetOperations.reverseRangeByScoreWithScores(RedisKeyConstant.top10, 0, 100, 0, 10);
        ThrowUtils.throwIf(typedTuples == null, ErrorCode.SYSTEM_ERROR, "Redis数据不存在 : Top10");
        log.info("Top10修复完成");
        return typedTuples;
    }

    public String recoveryUser(Long userId) {
        User user = userMapper.selectById(userId);
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR, "用户不存在: " + user);
        stringRedisTemplate.delete(RedisKeyConstant.getCompleteKey(RedisKeyConstant.userKey, userId.toString()));
        stringRedisTemplate.opsForValue().set(RedisKeyConstant.getCompleteKey(RedisKeyConstant.userKey, userId.toString()), JSONUtil.toJsonStr(user));
        String value = stringRedisTemplate.opsForValue().get(RedisKeyConstant.getCompleteKey(RedisKeyConstant.userKey, userId.toString()));
        ThrowUtils.throwIf(value == null || StrUtil.isBlankIfStr(value), ErrorCode.SYSTEM_ERROR, "Redis数据不存在 : user:" + userId);
        log.info("User修复完成");
        return value;
    }

    public String recoveryQuestion(Long questionId) {
        Question question = questionMapper.selectById(questionId);
        if (question == null) {
            // 设置空值，防止缓存穿透
            stringRedisTemplate.opsForValue().set(
                    RedisKeyConstant.getCompleteKey(RedisKeyConstant.questionKey, questionId.toString()),
                    RedisKeyConstant.NoneValue
            );
        } else {
            stringRedisTemplate.delete(RedisKeyConstant.getCompleteKey(RedisKeyConstant.questionKey, questionId.toString()));
            stringRedisTemplate.opsForValue().set(RedisKeyConstant.getCompleteKey(RedisKeyConstant.questionKey, questionId.toString()), JSONUtil.toJsonStr(question));
        }
        String value = stringRedisTemplate.opsForValue().get(RedisKeyConstant.getCompleteKey(RedisKeyConstant.questionKey, questionId.toString()));
        ThrowUtils.throwIf(value == null || StrUtil.isBlankIfStr(value), ErrorCode.SYSTEM_ERROR, "Redis数据不存在 : Question:" + questionId);
        log.info("Question修复完成");
        return value;
    }


    public Set<String> recoveryAdminIds() {
        Set<String> adminIds = userMapper.selectObjs(
                        new QueryWrapper<User>().select("id")
                                .eq("userRole", "admin")
                ).stream()
                .map(Object::toString)
                .collect(Collectors.toSet());
        for (String adminId : adminIds) {
            stringRedisTemplate.opsForSet().add(
                    RedisKeyConstant.adminIds,
                    adminId
            );
        }
        log.info("AdminIds修复完成");
        return stringRedisTemplate.opsForSet().members(
                RedisKeyConstant.adminIds
        );
    }

}
